import type { BaseStorage, StorageItem, StorageOptions } from './types';

/**
 * LocalStorage 存储实现
 */
export class LocalStorage<T> implements BaseStorage<T> {
  private readonly prefix: string;

  private readonly defaultTTL: number;

  private readonly encryption: {
    enabled: boolean;
    key: string;
  };

  private cleanupTimer: number | null = null;

  constructor(options: StorageOptions) {
    this.prefix = `${options.namespace}_${options.storeName || 'default'}_`;
    this.defaultTTL = options.defaultTTL || 0;
    this.encryption = {
      enabled: options.encryption?.enabled || false,
      key: options.encryption?.key || this.generateEncryptionKey(),
    };

    // 设置自动清理过期数据的定时器
    if (options.cleanupInterval && options.cleanupInterval > 0) {
      this.cleanupTimer = window.setInterval(() => {
        this.cleanupExpiredItems();
      }, options.cleanupInterval);
    }
  }

  /**
   * 生成简单的加密密钥
   */
  private generateEncryptionKey(): string {
    return Math.random().toString(36).substring(2, 15);
  }

  /**
   * 简单的加密函数
   */
  private encrypt(data: string): string {
    if (!this.encryption.enabled) return data;

    try {
      // 使用简单的字符偏移加密代替异或
      const result = [];
      for (let i = 0; i < data.length; i++) {
        const charCode = data.charCodeAt(i);
        const keyChar = this.encryption.key.charCodeAt(i % this.encryption.key.length);
        // 偏移字符，避免使用异或
        const encryptedChar = String.fromCharCode((charCode + keyChar) % 65536);
        result.push(encryptedChar);
      }
      return btoa(result.join(''));
    } catch (error) {
      console.error('加密失败:', error);
      return data;
    }
  }

  /**
   * 简单的解密函数
   */
  private decrypt(data: string): string {
    if (!this.encryption.enabled) return data;

    try {
      const decoded = atob(data);
      const result = [];
      for (let i = 0; i < decoded.length; i++) {
        const charCode = decoded.charCodeAt(i);
        const keyChar = this.encryption.key.charCodeAt(i % this.encryption.key.length);
        // 反向偏移字符，避免使用异或
        const decryptedChar = String.fromCharCode((charCode + 65536 - keyChar) % 65536);
        result.push(decryptedChar);
      }
      return result.join('');
    } catch (error) {
      console.error('解密失败:', error);
      return data;
    }
  }

  private getFullKey(key: string): string {
    return this.prefix + key;
  }

  private getAllKeys(): string[] {
    const keys: string[] = [];
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i);
      if (key?.startsWith(this.prefix)) {
        keys.push(key);
      }
    }
    return keys;
  }

  /**
   * 清理过期项目
   */
  private async cleanupExpiredItems(): Promise<void> {
    const now = Date.now();
    const keys = this.getAllKeys();

    for (const fullKey of keys) {
      try {
        const raw = localStorage.getItem(fullKey);
        if (raw) {
          const decrypted = this.decrypt(raw);
          const item: StorageItem<T> = JSON.parse(decrypted);

          if (item.expireAt && item.expireAt < now) {
            localStorage.removeItem(fullKey);
          }
        }
      } catch (error) {
        console.warn(`清理过期项目 ${fullKey} 失败:`, error);
      }
    }
  }

  async set(key: string, value: T, ttl?: number): Promise<void> {
    try {
      const fullKey = this.getFullKey(key);
      const expireAt = ttl || this.defaultTTL ? Date.now() + (ttl || this.defaultTTL) : undefined;

      const item: StorageItem<T> = {
        value,
        expireAt,
      };

      const serialized = JSON.stringify(item);
      const encrypted = this.encrypt(serialized);

      localStorage.setItem(fullKey, encrypted);
    } catch (error) {
      console.error('LocalStorage 写入失败:', error);
      throw new Error('存储写入失败');
    }
  }

  async get(key: string): Promise<T | null> {
    try {
      const fullKey = this.getFullKey(key);
      const raw = localStorage.getItem(fullKey);

      if (!raw) return null;

      const decrypted = this.decrypt(raw);
      const item: StorageItem<T> = JSON.parse(decrypted);

      // 检查是否过期
      if (item.expireAt && item.expireAt < Date.now()) {
        localStorage.removeItem(fullKey);
        return null;
      }

      return item.value;
    } catch (error) {
      console.error('LocalStorage 读取失败:', error);
      return null;
    }
  }

  async delete(key: string): Promise<void> {
    localStorage.removeItem(this.getFullKey(key));
  }

  async getAll(): Promise<T[]> {
    const results: T[] = [];
    const now = Date.now();
    try {
      const keys = this.getAllKeys();
      for (const fullKey of keys) {
        const raw = localStorage.getItem(fullKey);
        if (raw) {
          const decrypted = this.decrypt(raw);
          const item: StorageItem<T> = JSON.parse(decrypted);

          // 检查是否过期
          if (item.expireAt && item.expireAt < now) {
            localStorage.removeItem(fullKey);
            continue;
          }

          results.push(item.value);
        }
      }
    } catch (error) {
      console.error('LocalStorage 读取失败:', error);
    }
    return results;
  }

  async query(predicate: (item: T) => boolean): Promise<T[]> {
    const allItems = await this.getAll();
    return allItems.filter(predicate);
  }

  async clear(): Promise<void> {
    const keys = this.getAllKeys();
    for (const key of keys) {
      localStorage.removeItem(key);
    }
  }

  async has(key: string): Promise<boolean> {
    const value = await this.get(key);
    return value !== null;
  }

  async size(): Promise<number> {
    const items = await this.getAll();
    return items.length;
  }

  /**
   * 检查 LocalStorage 是否可用
   */
  static isAvailable(): boolean {
    try {
      const test = '__storage_test__';
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * 销毁实例，清理定时器
   */
  destroy(): void {
    if (this.cleanupTimer !== null) {
      window.clearInterval(this.cleanupTimer);
      this.cleanupTimer = null;
    }
  }
}
